package org.testis.data;

import org.testis.logging.AtofLogLevel;
import org.testis.logging.LogSenderService;
import java.util.Enumeration;
import javax.jms.JMSException;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.JmsException;
import org.springframework.jms.core.BrowserCallback;
import org.springframework.jms.core.JmsTemplate;

/**
 * A singleton class used for recieving test step  results.
 * @author nurhat
 */
public class TestStepResultSynchReciever extends TestStepResultReciever {

    private static TestStepResultSynchReciever m_reciever;
    private JmsTemplate m_jmsTemplate;
    private String m_lstMsgId;

    private TestStepResultSynchReciever() {
    }

    /**
     * A static method for creating singleton instance. This method
     * used in  spring framework supported configuration files
     * to create an instance of this class to be used globally.
     * @param m_jmsTemplate defines default destination of message
     * @return
     */
    public static TestStepResultSynchReciever createInstance(
            JmsTemplate jmsTemplate) {
        if (m_reciever == null) {
            m_reciever = new TestStepResultSynchReciever();
            m_reciever.m_jmsTemplate = jmsTemplate;
            m_reciever.setLastMsgId("");
        }

        return m_reciever;
    }

    public static TestStepResultSynchReciever getInstance() {
        return m_reciever;
    }

    /**
     * Use this method to recieve test step result synchronously
     * @return
     */
    public  TestStepResultDataObject recieve() {
        m_reciever.m_jmsTemplate.setReceiveTimeout(
                JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT);
        TestStepResultDataObject res = null;
        try {
            res = (TestStepResultDataObject) m_reciever.m_jmsTemplate.receiveAndConvert();
        } catch (JmsException ex) {
        }
        return res;
    }

    /**
     * Use this method to recieve test step result synchronously
     * @param timeout
     * @return
     */
    public  TestStepResultDataObject recieve(long timeout) {
        m_reciever.m_jmsTemplate.setReceiveTimeout(timeout);
        TestStepResultDataObject res = null;
        try {
            res = (TestStepResultDataObject) m_reciever.m_jmsTemplate.receiveAndConvert();
        } catch (JmsException ex) {
        }
        return res;
    }

    /**
     * Use this method to recieve test step result synchronously  with given msgid and timeout
     * @param timeout
     * @param msgId
     * @return
     */
    public  TestStepResultDataObject recieve(String msgId,
            long timeout) {
        //abortReciever(false);
        long roundCount = timeout / 1000;
        setLastMsgId(msgId);
        String msgSelector = "JMSCorrelationID='" + msgId + "'";
        m_reciever.m_jmsTemplate.setReceiveTimeout(500);
        TestStepResultDataObject res = null;
        for (long i = 0; i < roundCount; i++) {
            if (isAborted()) {
                break;
            }
            try {
                res = (TestStepResultDataObject) m_reciever.m_jmsTemplate.receiveSelectedAndConvert(msgSelector);
                if (res != null) {
                    break;
                }
            } catch (JmsException ex) {
                LogSenderService.putMessageOnQueue("TestStepResultSynchReciever",
                        AtofLogLevel.ERROR,
                        "Could not recieve test step result  data object..."
                        + ex.getMessage(),
                        msgId);
            }
            try {
                Thread.sleep(600);
            } catch (InterruptedException ex) {
            }
        }
        return res;

    }

    /**
     * Use this method to recieve test step result  synchronously with given msgid 
     * @param msgId
     * @return
     */
    public  TestStepResultDataObject recieve(String msgId) {
        setLastMsgId(msgId);
        String msgSelector = "JMSCorrelationID='" + msgId + "'";
        m_reciever.m_jmsTemplate.setReceiveTimeout(
                JmsTemplate.RECEIVE_TIMEOUT_INDEFINITE_WAIT);
        TestStepResultDataObject res = null;
        try {
            res = (TestStepResultDataObject) m_reciever.m_jmsTemplate.receiveSelectedAndConvert(msgSelector);
        } catch (JmsException ex) {
            LogSenderService.putMessageOnQueue("TestStepResultSynchReciever",
                    AtofLogLevel.ERROR,
                    "Could not recieve test step result  data object..."
                    + ex.getMessage(),
                    msgId);
        }
        return res;
    }

    /**
     * Use this method to retrieve  message count from synchronous results queue 
     * @param timeout
     * @return
     */
    public Integer retrieveCountOfMessages() {
        Integer count = 0;
        try {
            count = (Integer) m_reciever.m_jmsTemplate.browseSelected(
                    m_reciever.m_jmsTemplate.getDefaultDestinationName(),
                    new BrowserCallback() {

                        public Object doInJms(
                                Session session,
                                QueueBrowser queueBrowser)
                                throws JMSException {
                            Enumeration messages =
                                    queueBrowser.getEnumeration();
                            int count = 0;

                            while (messages.hasMoreElements()) {
                                count++;
                                messages.nextElement();
                            }
                            return new Integer(
                                    count);

                        }
                    });

        } catch (JmsException ex) {
        }
        return count;
    }

    /**
     * Use this method to retrieve  message count from synchronous results queue 
     * for the given message id
     * @param timeout
     * @return
     */
    public Integer retrieveCountOfMessages(String msgId) {
        Integer count = 0;
        String msgSelector = "JMSCorrelationID='" + msgId + "'";
        try {
            ActiveMQQueue q =
                    (ActiveMQQueue) m_reciever.m_jmsTemplate.getDefaultDestination();
            String dest = "ts_data_sync_response_queue";
            try {
                dest = q.getQueueName();
            } catch (JMSException ex) {
            }
            count = (Integer) m_reciever.m_jmsTemplate.browseSelected(
                    m_reciever.m_jmsTemplate.getDefaultDestinationName(),
                    dest,
                    new BrowserCallback() {

                        public Object doInJms(
                                Session session,
                                QueueBrowser queueBrowser)
                                throws JMSException {
                            Enumeration messages =
                                    queueBrowser.getEnumeration();
                            int count = 0;

                            while (messages.hasMoreElements()) {
                                count++;
                                messages.nextElement();
                            }
                            return new Integer(
                                    count);

                        }
                    });

        } catch (JmsException ex) {
            LogSenderService.putMessageOnQueue("TestStepResultSynchReciever",
                    AtofLogLevel.ERROR,
                    "Could not retrieve message count on asynch result queue..."
                    + ex.getMessage(),
                    msgId);
        }
        return count;
    }

    /**
     * @return the m_lstMsgId
     */
    public String getLastMsgId() {
        return m_lstMsgId;
    }

    /**
     * @param m_lstMsgId the m_lstMsgId to set
     */
    public void setLastMsgId(String lstMsgId) {
        this.m_lstMsgId = lstMsgId;
    }
}
